package cn.hollis.nft.turbo.order.infrastructure.sharding.algorithm;

import cn.hollis.nft.turbo.order.sharding.id.DistributeID;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.shardingsphere.sharding.api.sharding.complex.ComplexKeysShardingAlgorithm;
import org.apache.shardingsphere.sharding.api.sharding.complex.ComplexKeysShardingValue;
import org.apache.shardingsphere.sharding.api.sharding.hint.HintShardingAlgorithm;
import org.apache.shardingsphere.sharding.api.sharding.hint.HintShardingValue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
import java.util.stream.Collectors;
@Slf4j
public class TurboKeyShardingAlgorithm implements ComplexKeysShardingAlgorithm<String>, HintShardingAlgorithm<String> {

    private static Logger logger = LoggerFactory.getLogger(TurboKeyShardingAlgorithm.class);

    private Properties props;

    private static final String PROP_MAIN_COLUM = "mainColum";//buyer_id

    private static final String PROP_TABLE_COUNT = "tableCount";
    @Override
    public Properties getProps() {
        return props;
    }

    @Override
    public void init(Properties props) {
        this.props = props;
    }

    @Override
    public Collection<String> doSharding(Collection<String> availableTargetNames, ComplexKeysShardingValue<String> complexKeysShardingValue) {
        Collection<String> result = new HashSet<>();


        //buyer_id
        String mainColum = props.getProperty(PROP_MAIN_COLUM);
        // 获取分片键的值  39
        Collection<String> mainColums = complexKeysShardingValue.getColumnNameAndShardingValuesMap().get(mainColum);



        if (CollectionUtils.isNotEmpty(mainColums)) {
            int i=0;
            for (String colum : mainColums) {
                i++;
                String shardingTarget = calculateShardingTarget(colum);
              //  log.info("1.i={},colum:{},mainColums:{},shardingTarget:{}",i,colum,mainColums,shardingTarget);
                result.add(shardingTarget);
            }

            Collection<String> matchedTables = getMatchedTables(result, availableTargetNames);
            log.info("****分库分表策略，1.result:{},availableTargetNames:{},matchedTables:{}",result,availableTargetNames,matchedTables);
            return matchedTables;
        }
      //  log.info("2.result:{},availableTargetNames:{}",result,availableTargetNames);
        Map<String, Collection<String>> hashMap  = complexKeysShardingValue.getColumnNameAndShardingValuesMap();
        hashMap.remove(mainColum);
        Collection<String> otherColums = hashMap.keySet();
        if (CollectionUtils.isNotEmpty(otherColums)) {
            for (String colum : otherColums) {
                Collection<String> otherColumValues = hashMap.get(colum);
                for (String value : otherColumValues) {
                    String shardingTarget = extractShardingTarget(value);
                    result.add(shardingTarget);
                }
            }

            Collection<String> matchedTables = getMatchedTables(result, availableTargetNames);
            log.info("****分库分表策略，2.result:{},availableTargetNames:{},matchedTables:{}",result,availableTargetNames,matchedTables);
            return matchedTables;
        }

        return null;
    }

    /***
     * 获取表名称，例如：
     * @param results    result:
     *                      [0002],
     *                   availableTargetNames:
     *                      [trade_order_0000,
     *                      trade_order_0001,
     *                      trade_order_0002,
     *                      trade_order_0003],
     *                   matchedTables:
     *                      [trade_order_0002]
     * @param availableTargetNames
     * @return
     */
    private Collection<String> getMatchedTables(Collection<String> results, Collection<String> availableTargetNames) {
        Collection<String> matchedTables = new HashSet<>();
        for (String result : results) {
            matchedTables.addAll(availableTargetNames.parallelStream().filter(each -> each.endsWith(result)).collect(Collectors.toSet()));
        }
        return matchedTables;
    }

    /**
     * 根据订单id提取目标
     * @param orderId
     * @return
     */
    private String extractShardingTarget(String orderId) {
        return DistributeID.getShardingTable(orderId);

    }

    /**
     * 根据买家id获取分片结果
     * @param buyerId
     * @return
     */
    private String calculateShardingTarget(String buyerId) {
        String tableCount = props.getProperty(PROP_TABLE_COUNT);
        return DistributeID.getShardingTable(buyerId, Integer.parseInt(tableCount));
    }

    @Override
    public Collection<String> doSharding(Collection<String> collection, HintShardingValue<String> hintShardingValue) {
        log.info("do doSharding......");

        String logicTableName = hintShardingValue.getLogicTableName();
        Collection<String> shardingTargets = hintShardingValue.getValues();

        Collection<String> matchedTables = new HashSet<>();
        for (String shardingTarget : shardingTargets) {
            matchedTables.add(logicTableName + "_" + shardingTarget);
        }

        return CollectionUtils.intersection(collection, matchedTables);
    }
}
